from django.db.models import Q, Case, When, IntegerField, Value
from rest_framework import status
from rest_framework.exceptions import APIException
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from ..serializers import NoteSerializer, CreateNoteSerializer, TagSerializer, CategorySerializer, NoteTagSerializer, NoteCategorySerializer
from ..models import Note, Tag, Category, NoteTag, NoteCategory, NoteHistory
import logging

logger = logging.getLogger('apps')


class BaseResponse:
    @staticmethod
    def success(data=None, message="操作成功"):
        return Response({
            "status": "success",
            "message": message,
            "data": data
        })

    @staticmethod
    def error(message="操作失败", status=status.HTTP_400_BAD_REQUEST):
        return Response({
            "status": "error",
            "message": message
        }, status=status)


class AIProcessingError(APIException):
    status_code = 503
    default_detail = 'AI 处理服务暂时不可用'
    default_code = 'ai_service_unavailable'


# 获取用户的笔记列表
class NoteListView(APIView):
    """获取用户的笔记列表"""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            # 获取分页参数
            page = int(request.GET.get('page', 1))
            page_size = int(request.GET.get('page_size', 5))
            
            # 验证分页参数
            page = max(1, page)
            page_size = max(1, min(page_size, 100))  # 限制最大页面大小

            # 构建查询
            queryset = Note.objects.filter(user=request.user)

            # 处理置顶筛选
            is_pinned = request.GET.get('is_pinned')
            if is_pinned is not None:
                is_pinned = is_pinned.lower() == 'true'
                queryset = queryset.filter(is_pinned=is_pinned)

            # 排序
            queryset = queryset.order_by('-is_pinned', '-updated_at')

            # 分页
            paginator = Paginator(queryset, page_size)
            try:
                notes = paginator.page(page)
            except (EmptyPage, PageNotAnInteger):
                notes = paginator.page(1)

            # 序列化
            serializer = NoteSerializer(notes, many=True)

            return BaseResponse.success({
                'notes': serializer.data,
                'total': paginator.count,
                'total_pages': paginator.num_pages,
                'current_page': page,
                'has_next': notes.has_next(),
                'has_previous': notes.has_previous()
            })

        except Exception as e:
            logger.error(f"获取笔记列表失败: {str(e)}")
            return BaseResponse.error(str(e))


# 创建笔记
class CreateNoteView(APIView):
    """创建笔记"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            serializer = CreateNoteSerializer(
                data=request.data,
                context={'request': request}
            )
            if serializer.is_valid():
                note = serializer.save()
                return BaseResponse.success(
                    NoteSerializer(note).data,
                    '笔记创建成功'
                )
            return BaseResponse.error(serializer.errors)
        except Exception as e:
            logger.error(f"创建笔记失败: {str(e)}")
            return BaseResponse.error(str(e))


# 获取、更新或删除单个笔记
class NoteDetailView(APIView):
    """笔记详情视图"""
    permission_classes = [IsAuthenticated]

    def get_object(self, pk):
        try:
            return Note.objects.get(pk=pk)
        except Note.DoesNotExist:
            return None

    def get(self, request, pk):
        note = self.get_object(pk)
        if not note:
            return Response({
                'status': 'error',
                'message': '笔记不存在'
            }, status=status.HTTP_404_NOT_FOUND)

        serializer = NoteSerializer(note)
        return Response({
            'status': 'success',
            'data': serializer.data
        })

    def put(self, request, pk):
        note = self.get_object(pk)
        if not note:
            return Response({
                'status': 'error',
                'message': '笔记不存在'
            }, status=status.HTTP_404_NOT_FOUND)

        try:
            print("Received data for update:", request.data)

            # 如果是AI更新的内容，记录历史
            if 'update_type' in request.data:
                NoteHistory.objects.create(
                    note=note,
                    change_type='ai_update',
                    old_content=note.content,
                    new_content=request.data.get('content', '')
                )

            serializer = NoteSerializer(note, data=request.data, partial=True)
            if serializer.is_valid():
                note = serializer.save()
                return Response({
                    'status': 'success',
                    'data': NoteSerializer(note).data
                })

            print("Validation errors:", serializer.errors)
            return Response({
                'status': 'error',
                'message': serializer.errors
            }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"更新笔记失败: {str(e)}")
            return Response({
                'status': 'error',
                'message': str(e)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def delete(self, request, pk):
        note = self.get_object(pk)
        if not note:
            return Response({
                'status': 'error',
                'message': '笔记不存在'
            }, status=status.HTTP_404_NOT_FOUND)

        note.delete()
        return Response({
            'status': 'success',
            'message': '删除成功'
        })


# 获取所有标签
class TagListView(APIView):
    """获取所有标签"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    def get(self, request):
        # 获取所有标签
        tags = Tag.objects.all()
        # 使用 TagSerializer 对标签数据进行序列化
        serializer = TagSerializer(tags, many=True)
        return Response(serializer.data)


# 获取、更新或删除单个标签
class TagDetailView(APIView):
    """获取、更新或删除单个标签"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    # 获取单个标签
    def get(self, request, pk):
        try:
            # 尝试根据 pk 获取标签
            tag = Tag.objects.get(pk=pk)
        except Tag.DoesNotExist:
            # 如果标签不存在，返回 404 错误
            return Response({"detail": "Tag not found."}, status=status.HTTP_404_NOT_FOUND)

        # 使用 TagSerializer 序列化标签数据
        serializer = TagSerializer(tag)
        return Response(serializer.data)

    # 更新单个标签
    def put(self, request, pk):
        try:
            # 尝试根据 pk 获取标签
            tag = Tag.objects.get(pk=pk)
        except Tag.DoesNotExist:
            # 如果标签不存在，返回 404 错误
            return Response({"detail": "Tag not found."}, status=status.HTTP_404_NOT_FOUND)

        # 使用 TagSerializer 对更新数据进行验证
        serializer = TagSerializer(tag, data=request.data)
        if serializer.is_valid():  # 如果数据有效
            serializer.save()  # 保存更新后的标签数据
            return Response({
                'message': 'Tag updated successfully',
                'tag': serializer.data  # 返回更新后的标签数据
            })
        # 如果数据无效，返回错误信息
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # 删除单个标签
    def delete(self, request, pk):
        try:
            # 尝试根据 pk 获取标签
            tag = Tag.objects.get(pk=pk)
        except Tag.DoesNotExist:
            # 如果标签不存在，返回 404 错误
            return Response({"detail": "Tag not found."}, status=status.HTTP_404_NOT_FOUND)

        tag.delete()  # 删除标签
        return Response({"message": "Tag deleted successfully"}, status=status.HTTP_204_NO_CONTENT)


# 获取所有分类
class CategoryListView(APIView):
    """获取所有分类"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    def get(self, request):
        # 获取所有分类
        categories = Category.objects.all()
        # 使用 CategorySerializer 对分类数据进行序列化
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)


# 获取、更新或删除单个分类
class CategoryDetailView(APIView):
    """获取、更新或删除单个分类"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    # 获取单个分类
    def get(self, request, pk):
        try:
            # 尝试根据 pk 获取分类
            category = Category.objects.get(pk=pk)
        except Category.DoesNotExist:
            # 如果分类不存在，返回 404 错误
            return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND)

        # 使用 CategorySerializer 序列化分类数据
        serializer = CategorySerializer(category)
        return Response(serializer.data)

    # 更新单个分类
    def put(self, request, pk):
        try:
            # 尝试根据 pk 获取分类
            category = Category.objects.get(pk=pk)
        except Category.DoesNotExist:
            # 如果分类不存在，返回 404 错误
            return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND)

        # 使用 CategorySerializer 对更新数据进行验证
        serializer = CategorySerializer(category, data=request.data)
        if serializer.is_valid():  # 如果数据有效
            serializer.save()  # 保存更新后的分类数据
            return Response({
                'message': 'Category updated successfully',
                'category': serializer.data  # 返回更新后的分类数据
            })
        # 如果数据无效，返回错误信息
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # 删除单个分类
    def delete(self, request, pk):
        try:
            # 尝试根据 pk 获取分类
            category = Category.objects.get(pk=pk)
        except Category.DoesNotExist:
            # 如果分类不存在，返回 404 错误
            return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND)

        category.delete()  # 删除分类
        return Response({"message": "Category deleted successfully"}, status=status.HTTP_204_NO_CONTENT)


# 获取所有笔记标签关联
class NoteTagListView(APIView):
    """获取所有笔记标签关联"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    def get(self, request):
        # 获取所有笔记标签关联
        note_tags = NoteTag.objects.all()
        # 使用 NoteTagSerializer 对笔记标签关联数据进行序列化
        serializer = NoteTagSerializer(note_tags, many=True)
        return Response(serializer.data)


# 获取所有笔记分类关联
class NoteCategoryListView(APIView):
    """获取所有笔记分类关联"""
    permission_classes = [IsAuthenticated]  # 确保只有认证过的用户才能访问

    def get(self, request):
        # 获取所有笔记分类关联
        note_categories = NoteCategory.objects.all()
        # 使用 NoteCategorySerializer 对笔记分类关联数据进行序列化
        serializer = NoteCategorySerializer(note_categories, many=True)
        return Response(serializer.data)


# 搜索视图
class NoteSearchView(APIView):
    """笔记搜索视图"""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            # 打印请求信息
            logger.info(f"Request GET params: {request.GET}")
            logger.info(f"Request path: {request.path}")
            logger.info(f"Request headers: {request.headers}")

            # 获取并验证搜索参数
            search = request.GET.get('search', '')
            logger.info(f"Raw search term: '{search}'")

            # 验证搜索词
            if not search or not search.strip():
                logger.warning("Empty search term received")
                return BaseResponse.error("搜索关键词不能为空", status=status.HTTP_400_BAD_REQUEST)

            # 获取分页参数
            try:
                page = int(request.GET.get('page', 1))
                page_size = int(request.GET.get('page_size', 10))
                page = max(1, page)
                page_size = max(1, min(page_size, 100))
            except (ValueError, TypeError):
                logger.warning("Invalid page parameters, using defaults")
                page = 1
                page_size = 10

            # 处理搜索词
            search = search.strip()
            search_terms = [term.strip() for term in search.split() if term.strip()]

            # 构建搜索查询
            search_query = Q()
            for term in search_terms:
                title_query = Q(title__icontains=term)
                content_query = Q(content__icontains=term)
                tag_query = Q(tags__name__icontains=term)
                search_query |= (title_query | content_query | tag_query)

            # 应用查询并排序
            queryset = (
                Note.objects.filter(user=request.user)
                .filter(search_query)
                .annotate(
                    relevance=Case(
                        When(title__iexact=search, then=Value(100)),
                        When(title__icontains=search, then=Value(80)),
                        When(content__icontains=search, then=Value(50)),
                        default=Value(0),
                        output_field=IntegerField(),
                    )
                )
                .order_by('-relevance', '-updated_at')
                .distinct()
            )

            # 分页处理
            paginator = Paginator(queryset, page_size)
            try:
                notes = paginator.page(page)
            except (EmptyPage, PageNotAnInteger):
                notes = paginator.page(1)

            # 序列化并处理结果
            serializer = NoteSerializer(notes, many=True)
            search_results = []
            
            for note in serializer.data:
                match_positions = self._get_match_positions(note, search_terms)
                note['match_context'] = match_positions
                search_results.append(note)

            return BaseResponse.success({
                'notes': search_results,
                'total': paginator.count,
                'total_pages': paginator.num_pages,
                'current_page': page,
                'has_next': notes.has_next(),
                'has_previous': notes.has_previous(),
                'search_terms': search_terms
            })

        except Exception as e:
            logger.error(f"Search failed with error: {str(e)}")
            return BaseResponse.error(str(e))

    def _get_match_positions(self, note, search_terms):
        """获取匹配位置和上下文"""
        match_positions = []
        content = note.get('content', '')
        title = note.get('title', '')
        
        for term in search_terms:
            # 标题匹配
            title_pos = title.lower().find(term.lower())
            if title_pos != -1:
                match_positions.append({
                    'type': 'title',
                    'position': title_pos,
                    'text': title[max(0, title_pos-20):title_pos+len(term)+20]
                })
            
            # 内容匹配
            content_pos = content.lower().find(term.lower())
            if content_pos != -1:
                match_positions.append({
                    'type': 'content',
                    'position': content_pos,
                    'text': content[max(0, content_pos-50):content_pos+len(term)+50]
                })
        
        return match_positions